package cn.tedu.gateway.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.*;

/**
 * 封装生成token和验证token方法
 */
@Slf4j
@Component
public class JWTUtil {
    /**
     * 盐值
     * 生成token header.payload.signature
     */
    private static String SIGNATURE="token!Q2W#E$RW";


    /**
     * 生成访问token
     * @param map
     * @return
     */
    public static String getVisitToken(Map<String,Object> map){
        Calendar instance = Calendar.getInstance();
        //30分钟
        instance.add(Calendar.DAY_OF_MONTH, 2);
        //创建jwt builder
        JWTCreator.Builder builder = JWT.create();

        //payload,用遍历避免多个键值对
        map.forEach((k,v)->{
            builder.withClaim(k,v+"");
        });
        //指定令牌过期时间,设置签名返回token
        return builder.withExpiresAt(instance.getTime())
                .sign(Algorithm.HMAC256(SIGNATURE));
    }

    /**
     * 生成刷新Token.
     *
     * @param claims 用于存放Token中的信息
     * @return 生成的刷新Token字符串
     */
    public static String getRefreshToken(Map<String, Object> claims) {
        Calendar instance = Calendar.getInstance();
        // 7天过期，可以根据实际情况调整有效期
        instance.add(Calendar.DAY_OF_MONTH, 7);
        // 创建jwt builder
        JWTCreator.Builder builder = JWT.create();

        // 添加必要的声明，如用户ID等
        claims.forEach((k, v) -> {
            builder.withClaim(k, v.toString());
        });

        // 添加一个唯一的Token ID（可选）
        builder.withClaim("jti", UUID.randomUUID().toString());

        // 指定令牌过期时间, 设置签名返回token
        return builder.withExpiresAt(instance.getTime())
                .sign(Algorithm.HMAC256(SIGNATURE));
    }

    /**
     * 验证访问token合法性
     * @param visitToken
     */
    public static String verify(String visitToken,String refreshToken){

        DecodedJWT verify = JWT.require(Algorithm.HMAC256(SIGNATURE)).build().verify(visitToken);
        // 获取JWT的过期时间
        long expiration = verify.getExpiresAt().getTime();

        //获取jwt过期时间前1分钟的时间戳
        long oneMinuteBeforeExpiration = expiration - (60 * 1000);


        // 获取当前时间
        long currentTime = System.currentTimeMillis();

        // 检查JWT是否已经过期
        if (oneMinuteBeforeExpiration <= currentTime) {
            System.out.println("Token接近过期");
            return refreshVisitToken(refreshToken);
        } else {
            System.out.println("Token未过期");
            return null;
        }
    }

    /**
     * 验证刷新Token.
     *
     * @param refreshToken 要验证的刷新Token字符串
     * @return 如果Token有效，返回true；否则返回false
     */
    public static boolean validateRefreshToken(String refreshToken) {
        try {
            DecodedJWT jwt = JWT.require(Algorithm.HMAC256(SIGNATURE))
                    .build()
                    .verify(refreshToken);

            // 获取JWT的过期时间
            Date expirationTime = jwt.getExpiresAt();

            // 获取当前时间
            Date currentTime = new Date();

            // 检查JWT是否已经过期
            //expirationTime.before(currentTime);  为true表示已经过期  为false表示未过期
            return expirationTime.before(currentTime);
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 通过刷新Token刷新访问Token.
     *
     * @param refreshToken 要验证的刷新Token字符串
     * @return 新的访问Token字符串
     */
    public static String refreshVisitToken(String refreshToken) {
        // 验证刷新Token的有效性
        if (validateRefreshToken(refreshToken)) {
            throw new SecurityException("Invalid or expired refresh token.");
        }

        // 获取原始访问Token中的所有声明
        Map<String, Object> claims = getUserInfo(refreshToken);

        // 创建新的访问Token
        return getVisitToken(claims);
    }

    /*
     * 通过token获取token信息
     * */
    public static DecodedJWT getTokenInfo(String token ){
        return   JWT.require(Algorithm.HMAC256(SIGNATURE)).build().verify(token);

    }

    /*
     * 通过token获取用户信息
     * */
    public static Map<String,Object> getUserInfo(String token){
        DecodedJWT tokenInfo = JWT.require(Algorithm.HMAC256(SIGNATURE)).build().verify(token);
        Map<String, Claim> claims = tokenInfo.getClaims();
        Set<Map.Entry<String, Claim>> entries = claims.entrySet();
        Map<String,Object> map = new HashMap<>();
        for (Map.Entry<String, Claim> entry : entries) {
            map.put(entry.getKey(),entry.getValue().as(Object.class));
        }
        return map;
    }


}
